package io.github.kevinzhwl.edgetts.util;

import io.github.kevinzhwl.edgetts.constant.EdgeApiUrlConstants;
import lombok.experimental.UtilityClass;
import org.apache.commons.lang3.StringUtils;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@UtilityClass
public class CommunicateUtil {

  static Pattern voicePattern1 = Pattern.compile("^([a-z]{2,})-([A-Z]{2,})-(.+Neural)$");
  static Pattern voicePattern2 = Pattern.compile("^Microsoft Server Speech Text to Speech Voice \\(.+,.+\\)$");

  public String mkVoiceInfo(String voice) {
    if (voice == null) {
      voice = "Microsoft Server Speech Text to Speech Voice (en-US, AriaNeural)";
    }
    Matcher match = voicePattern1.matcher(voice);
    if (match.matches()) {
      String lang = match.group(1);
      String region = match.group(2);
      String name = match.group(3);
      if (name.contains("-")) {
        region = region + "-" + name.substring(0, name.indexOf("-"));
        name = name.substring(name.indexOf("-") + 1);

      }
      voice = String.format("Microsoft Server Speech Text to Speech Voice (%s-%s, %s)", lang, region, name);
    }

    if (voicePattern2.matcher(voice).matches()) {
      return voice;
    }
    return null;

  }

  public String mkAudioFormat(String dateStr, String format) {
    return "X-Timestamp:" + dateStr + "\r\n" +
      "Content-Type:application/json; charset=utf-8\r\n" +
      "Path:speech.config\r\n\r\n" +
      "{\"context\":{\"synthesis\":{\"audio\":{\"metadataoptions\":{" +
      "\"sentenceBoundaryEnabled\":\"false\",\"wordBoundaryEnabled\":\"true\"}," +
      "\"outputFormat\":\"" + format + "\"}}}}\n";
  }


  public String mkSsml(String voiceName, String voiceRate, String voiceVolume, String content) {
    return "<speak version='1.0' xmlns='http://www.w3.org/2001/10/synthesis' xml:lang='en-US'>" +
      "<voice name='" + voiceName + "'><prosody pitch='+0Hz' rate='" + voiceRate + "' volume='" + voiceVolume + "'>" +
      content + "</prosody></voice></speak>";
  }


  public String mkSsmlHeadersPlusData(String requestId, String timestamp, String ssml) {
    return "X-RequestId:" + requestId + "\r\n" +
      "Content-Type:application/ssml+xml\r\n" +
      "X-Timestamp:" + timestamp + "Z\r\n" +
      "Path:ssml\r\n\r\n" + ssml;
  }

  public int calcMaxMessageSize(String voice, String rate, String volume) {
    /*Calculates the maximum message size for the given voice, rate, and volume.

    Returns:
        int: The maximum message size.
    */

    double pow = Math.pow(2, 16);
    int websocket_max_size = (int) pow;
    final String content = mkSsmlHeadersPlusData(connectId(), dateToString(), mkSsml("", voice, rate, volume));

    //margin of error
    int overhead_per_message = content.length() + 50;
    return websocket_max_size - overhead_per_message;
  }

  public String dateToString() {
    return dateToString(new Date());
  }

  public String dateToString(Date date) {
    SimpleDateFormat sdf = new SimpleDateFormat("EEE MMM dd yyyy HH:mm:ss 'GMT'Z (zzzz)");
    return sdf.format(date);
  }


  public String connectId() {
    return UUID.randomUUID().toString().replace("-", "");
  }

  public String removeIncompatibleCharacters(String input) {
    if (StringUtils.isBlank(input)) {
      return null;
    }
    StringBuilder output = new StringBuilder();
    for (int i = 0; i < input.length(); i++) {
      char c = input.charAt(i);
      int code = (int) c;
      if ((0 <= code && code <= 8) || (11 <= code && code <= 12) || (14 <= code && code <= 31)) {
        output.append(" ");
      } else {
        output.append(c);
      }
    }
    return output.toString();
  }


  public Map<String, String> getVoiceListHttpHeaders() {
    Map<String, String> headers = new HashMap<>();
    headers.put("Authority", "speech.platform.bing.com");
    headers.put("Sec-CH-UA", "\" Not;A Brand\";v=\"99\", \"Microsoft Edge\";v=\"91\", \"Chromium\";v=\"91\"");
    headers.put("Sec-CH-UA-Mobile", "?0");
    headers.put("User-Agent", EdgeApiUrlConstants.Edge.HTTP_USER_AGENT);
    headers.put("Accept", "*/*");
    headers.put("Sec-Fetch-Site", "none");
    headers.put("Sec-Fetch-Mode", "cors");
    headers.put("Sec-Fetch-Dest", "empty");
    headers.put("Accept-Encoding", "gzip, deflate, br");
    headers.put("Accept-Language", "en-US,en;q=0.9");

    return headers;
  }

  public Map<String, String> getCommunicateHttpHeaders() {

    Map<String, String> headers2 = new HashMap<>();
    headers2.put("Pragma", "no-cache");
    headers2.put("Cache-Control", "no-cache");
    headers2.put("Origin", EdgeApiUrlConstants.Edge.HTTP_ORIGIN);
    headers2.put("User-Agent", EdgeApiUrlConstants.Edge.HTTP_USER_AGENT);
    headers2.put("Accept-Encoding", "gzip, deflate, br");
    headers2.put("Accept-Language", "en-US,en;q=0.9");
    return headers2;
  }
}
